package eScrum.dao.impl;

import java.util.List;

import eScrum.dao.UserDao;
import eScrum.entities.ClassicUser;
import eScrum.entities.Developer;
import eScrum.entities.PowerUser;
import eScrum.entities.User;
import eScrum.entities.UserRole;
import eScrum.entities.UserSearchCriteria;
import eScrum.entities.UserStatus;

import org.hibernate.Query;
import org.springframework.orm.hibernate4.HibernateTransactionManager;

public class UserDaoImpl extends HibernateTransactionManager implements UserDao {

	private static final long serialVersionUID = 2484279744412331501L;

	public User saveOrUpdate(User u) {

		if (u.getRole() == UserRole.POWERUSER) {
			if (u.getId() <= 0) {
				if (u.getPoweruser() == null) {
					PowerUser powerUser = new PowerUser();
					powerUser.setName(concatName(u.getFirstName(), u.getLastName()));
					u.setPoweruser(powerUser);
					getSessionFactory().getCurrentSession().saveOrUpdate(powerUser);
				}
			} else if (u.getId() > 0) {
				PowerUser powerUser = u.getPoweruser();
				powerUser.setName(concatName(u.getFirstName(), u.getLastName()));
				u.setPoweruser(powerUser);
				getSessionFactory().getCurrentSession().saveOrUpdate(powerUser);
			}
		}
		if (u.getRole() == UserRole.DEVELOPER) {
			if (u.getId() <= 0) {
				if (u.getDeveloper() == null) {
					Developer developer = new Developer();
					developer.setName(concatName(u.getFirstName(), u.getLastName()));
					u.setDeveloper(developer);
					getSessionFactory().getCurrentSession().saveOrUpdate(developer);
				}
			} else if (u.getId() > 0) {
				Developer developer = u.getDeveloper();
				developer.setName(concatName(u.getFirstName(), u.getLastName()));
				u.setDeveloper(developer);
				getSessionFactory().getCurrentSession().saveOrUpdate(developer);
			}
		}
		if (u.getRole() == UserRole.ClASSICUSER) {
			if (u.getId() <= 0) {
				if (u.getClassicuser() == null) {
					ClassicUser classicuser = new ClassicUser();
					classicuser.setName(concatName(u.getFirstName(), u.getLastName()));
					u.setClassicuser(classicuser);
					getSessionFactory().getCurrentSession().saveOrUpdate(classicuser);
				}
			} else if (u.getId() > 0) {
				ClassicUser classicUser = u.getClassicuser();
				classicUser.setName(concatName(u.getFirstName(), u.getLastName()));
				u.setClassicuser(classicUser);
				getSessionFactory().getCurrentSession().saveOrUpdate(classicUser);
			}
		}
		getSessionFactory().getCurrentSession().saveOrUpdate(u);
		return (User) getSessionFactory().getCurrentSession().createQuery("from User u where u.username = :username")
				.setParameter("username", u.getUsername()).uniqueResult();
	}

	public User exists(String username) {
		Query query = getSessionFactory().getCurrentSession().createQuery("from User u where u.username = :username");
		query.setParameter("username", username);
		List<?> users = query.list();
		if (users.isEmpty())
			return null;
		else
			return (User) users.get(0);
	}

	public boolean signIn(String username, String password) {
		Query query = getSessionFactory().getCurrentSession().createQuery("from User u where u.username = :username and u.password = :password");
		query.setParameter("username", username);
		query.setParameter("password", password);
		List<?> users = query.list();
		if (users.isEmpty())
			return false;
		else
			return true;
	}

	public void roleTest(UserStatus u) {

		getSessionFactory().getCurrentSession().saveOrUpdate(u);

	}

	@SuppressWarnings("unchecked")
	public List<User> findAll() {
		Query query = getSessionFactory().getCurrentSession().createQuery("from User u");
		return (List<User>) query.list();
	}

	public void deleteUser(String id) {
		Query query = getSessionFactory().getCurrentSession().createQuery("from User where id = :id ");
		query.setParameter("id", Long.parseLong(id));
		User user = (User) query.list().get(0);
		getSessionFactory().getCurrentSession().delete(user);

	}

	public User findById(long id) {
		Query query = getSessionFactory().getCurrentSession().createQuery("from User u where id = :id");
		query.setParameter("id", id);
		List<?> users = query.list();
		if (users.isEmpty())
			return null;
		else
			return (User) users.get(0);
	}

	private String concatName(String firstName, String lastName) {
		StringBuilder builder = new StringBuilder();
		if (firstName != null) {
			builder.append(firstName).append(" ");
		}
		if (lastName != null) {
			builder.append(lastName);
		}
		return builder.toString();
	}

	@SuppressWarnings("unchecked")
	public List<User> findUsersByRange(int start, int count, UserSearchCriteria userSearchCriteria) {
		// LOGGER.debug("findUsersByRange");
		String whereExpression = buildWhereExpression(userSearchCriteria);
		String hql = " from User u ";
		if (whereExpression.length() > 0) {
			hql += " where " + whereExpression;
		}
		Query query = getSessionFactory().getCurrentSession().createQuery(hql);
		query.setFirstResult(start);
		query.setMaxResults(count);
		return (List<User>) query.list();
	}

	private String buildWhereExpression(UserSearchCriteria userSearchCriteria) {
		StringBuilder whereExpression = new StringBuilder();
		if (userSearchCriteria.isAdmin()) {
			whereExpression.append("(");
			whereExpression.append("role = 'ADMIN'");
		}
		if (userSearchCriteria.isClassicUser()) {
			appendOrExpression(whereExpression, " role = 'CLASSICUSER'");

		}
		if (userSearchCriteria.isAdmin()) {
			appendOrExpression(whereExpression, " role = 'ADMIN'");
		}
		if (userSearchCriteria.isiDeveloper()) {
			appendOrExpression(whereExpression, " role = 'DEVELOPER'");
		}
		if (userSearchCriteria.isPowerUser()) {
			appendOrExpression(whereExpression, " role = 'POWERUSER'");
		}
		if (whereExpression.length() > 0) {
			whereExpression.append(")");
		}
		if ((userSearchCriteria.isActive() || userSearchCriteria.isSuspended()) && whereExpression.length() > 0) {
			whereExpression.append(" AND ");
		}
		if (userSearchCriteria.isActive()) {
			whereExpression.append("(");
			whereExpression.append("status = 'ACTIVE'");
		}
		if (userSearchCriteria.isSuspended()) {
			if (whereExpression.length() > 0) {
				if (userSearchCriteria.isActive()) {
					whereExpression.append(" OR ");
				}
			}
			whereExpression.append("status = 'SUSPENDED'");
		}
		if (userSearchCriteria.isActive() || userSearchCriteria.isSuspended()) {
			whereExpression.append(")");
		}

		return whereExpression.toString();
	}

	private void appendOrExpression(StringBuilder whereExpression, String expression) {
		if (whereExpression.length() > 0) {
			whereExpression.append(" OR ");

		} else
			whereExpression.append(" ( ");
		whereExpression.append(expression);
	}

	public long userSize(UserSearchCriteria userSearchCriteria) {
		// LOGGER.debug("userSize(UserSearchCriteria userSearchCriteria)");
		String whereExpression = buildWhereExpression(userSearchCriteria);
		String hql = " select count(*) from User u";
		if (whereExpression.length() > 0) {
			hql += " where " + whereExpression;
		}
		Query query = getSessionFactory().getCurrentSession().createQuery(hql);
		return (Long) query.uniqueResult();
	}

}
